package com.frank.loadinglibrary.special.dot.anim;

import com.frank.loadinglibrary.special.dot.Config;
import com.frank.loadinglibrary.special.dot.circle.BaseCircle;
import com.frank.loadinglibrary.special.dot.circle.FixCircle;
import com.frank.loadinglibrary.special.dot.circle.WolfCircle;
import com.frank.loadinglibrary.special.element.DotLoadingElement;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.Path;

import java.util.ArrayList;

/**
 * @author SUQI
 * @date 2021/5/27
 * @description
 **/
public class LoopCircleAnimator extends AnimatorValue {
    public final static int DURATION = Config.DURATION_LOOP;
    private DotLoadingElement element;
    private ArrayList<FixCircle> mRabbits = new ArrayList<>();
    private WolfCircle mWolf;
    private float startX;
    private float startY;
    private float centerX;
    private float centerY;
    private float bigR;
    private float rate = 1.2f;

    private int mAliveRabbits = 0;

    private Path mPath;
    private int mPathDegree = -1;

    public LoopCircleAnimator(DotLoadingElement element) {
        this.element = element;

        initComponent();
        initAnimator();

        mPath = new Path();
    }

    /**
     * 设置六个圆点以及运动的圆点
     */
    private void initComponent() {

        startX = Config.START_X;
        startY = Config.START_Y;
        centerX = Config.CENTER_X;
        centerY = Config.CENTER_Y;
        bigR = Config.BIG_CIRCLE_RADIUS;

        // create 6 rabbits
        int r = (int) (Math.min(element.getWidth(), element.getHeight()) / 30);
        int degree = 0;
        for (int i = 0; i < Config.RABBIT_NUM; i++) {
            mRabbits.add(new FixCircle(startX, startY, r, degree));
            degree += Config.DEGREE_GAP;
        }

        // create wolf
        if (mWolf == null) {
            mWolf = new WolfCircle(startX, startY, (int) (rate * r), 0);
        }

    }

    /**
     * 设置animator的参数
     */
    private void initAnimator() {

        this.setDuration(DURATION);

        this.setValueUpdateListener((animatorValue, v) -> {
            float degree = 360 * v;
            startActivities(degree);
            element.getCallback().reflushComponent();
        });
    }

    /**
     * 开始运动,目的是旋转一圈,所以是从0-360度
     *
     * @param degree
     */
    private void startActivities(float degree) {
        mWolf.runTo(degree);
        // 运动小球增大
        mWolf.bigger(degree / Config.DEGREE_GAP * 2);
        // 这里有一个细节动作,当运动小球靠近时,静止的圆点会进行一个震动.震动是通过设置其状态来完成的
        for (FixCircle rabbit : mRabbits) {
            if (mAliveRabbits < 6 && rabbit.getState() == FixCircle.DIED
                    && rabbit.getDegree() < degree) {
                rabbit.setState(FixCircle.ALIVE);
                mAliveRabbits++;
            }
            if (mWolf.getDegree() - rabbit.getDegree() > 0 && mWolf.getDegree() - rabbit.getDegree() <= 40) {
                float deg = (mWolf.getDegree() - rabbit.getDegree());
                mPathDegree = (int) (rabbit.getDegree() + 1);
                int distance = (int) (Math.sin(Math.toRadians(deg)) * bigR);
                updatePath(distance, deg);

            }

            if (rabbit.getDegree() - mWolf.getDegree() > 0 && rabbit.getDegree() - mWolf.getDegree() < 60) {
                rabbit.setState(FixCircle.DANGER);
            } else if (rabbit.getState() == FixCircle.DANGER) {
                rabbit.setState(FixCircle.ALIVE);
            }
        }
    }

    /**
     * 黏着效果实现,这里的黏着效果是由4个点完成的,外加两个控制点.
     *
     * @param distance
     */
    private void updatePath(int distance, float deg) {
        // TODO 塞贝尔曲线还有一些问题,由于是通过旋转角度实现两个圆点之间的链接,所以会有偏差,现在暂且通过微调解决
        mPath.reset();
        float x1 = startX;
        float y1 = startY - mRabbits.get(0).getRadius();

        float x2 = startX;
        float y2 = startY + mRabbits.get(0).getRadius();

        float distanceX = (float) (mWolf.getRadius() * Math.sin(Math.toRadians(deg)));

        float x3 = startX + distance - distanceX;
        float y3 = (float) (startY + bigR - bigR * Math.cos(Math.toRadians(deg)) + mWolf.getRadius()) - 15;

        float x4 = startX + distance + distanceX;
        float y4 = (float) (startY + bigR - bigR * Math.cos(Math.toRadians(deg)) - mWolf.getRadius() + 15);

        float controlX1T4 = (float) (startX + bigR * Math.sin(Math.toRadians(deg / 2)));
        float controlY1T4 = (float) (startY + bigR - bigR * Math.cos(Math.toRadians(deg / 2)));
        mPath.moveTo(x1, y1);
        mPath.lineTo(x2, y2);
        mPath.quadTo(controlX1T4, controlY1T4, x3, y3);
        mPath.lineTo(x4, y4);
        mPath.quadTo(controlX1T4, controlY1T4, x1, y1);
        mPath.close();
    }

    /**
     * 绘制圆点
     *
     * @param canvas
     * @param paint
     */
    public void draw(Canvas canvas, Paint paint) {

        for (BaseCircle rabbit : mRabbits) {
            rabbit.draw(canvas, paint, centerX, centerY);
        }

        mWolf.draw(canvas, paint, centerX, centerY);

        if (mPathDegree > 0) {
            drawPath(canvas, paint);
        }

    }

    /**
     * 绘制黏着部分
     *
     * @param canvas
     * @param paint
     */
    public void drawPath(Canvas canvas, Paint paint) {
        canvas.save();
        canvas.rotate(mPathDegree, centerX, centerY);
        canvas.drawPath(mPath, paint);
        canvas.restore();
        mPathDegree = -1;
    }

    public WolfCircle getWolf() {
        return mWolf;
    }

    public ArrayList<FixCircle> getRabbits() {
        return mRabbits;
    }
}
